#include "Indice.h"
#include "Contexto.h"
#include <iostream>

Indice::Indice()
{
	for(int i = 1; i<255256; i++)
	{
		contextos[i] = new Contexto(MAX_SIZE);
	}
}

Indice::~Indice()
{
	delete[] contextos;
}

int Indice::obtenerPosContexto(char car1, char car2)
{
	int posContexto = 0;
	int aux1 = 0; 
	int aux2 = 0;
	aux1 = (int) car1;
	aux2 = (int) car2;
	aux1 = aux1*1000;
	posContexto = aux1 + aux2;
	return posContexto;
}

Contexto* Indice::obtenerContexto(int posContexto)
{
	Contexto *cont = contextos[posContexto];
	if ( cont == NULL )
	{
		contextos[posContexto] = new Contexto();
	}
	return cont;
}
 
Compresion* Indice::generarCompresion(Compresion *compr, BloqueTexto bloque)
{
	int posCtx = obtenerPosContexto(compr->getContexto(0), compr->getContexto(1));
	Contexto *contexto = obtenerContexto(posCtx);
	int size = contexto->getSize();
	
	// Si la lista de predicciones en esa posición esta vacía, la agrego en la primer posición
	// con el puntaje inicial.
	if ( size == 0)
	{
		contexto->addPrediccion(compr->getPosicionCaracterActual()); 
		compr->setLongitud(0);
		return compr;
	}
	
	Prediccion* primerPred = contexto->getPrimerPrediccion();
	int posCaracterActual = compr->getPosicionCaracterActual();
	int posCaracterPrediccion = primerPred->getPosicion();
	char caracterPrediccion = bloque.getCaracterEnPos(primerPred->getPosicion());
	char caracterActual = bloque.getCaracterEnPos(posCaracterActual);	
	
	int match = 0;
	while( caracterActual == caracterPrediccion && ((match + posCaracterPrediccion) < posCaracterActual) )
	{
		match ++;
		caracterActual = bloque.getCaracterEnPos(posCaracterActual + match);
		caracterPrediccion = bloque.getCaracterEnPos(posCaracterPrediccion + match);

	}
	//si no hubo match, resto puntaje a la primer predicción e intento agregar la nueva.
	//si la nueva predicción coincide con alguna otra le sumo puntaje de coincidencia (si el
	//puntaje es 0 la reemplazo por esta nueva).
	//Se controla que en una posible incorporación de una nueva predicción, esta no esté repetida.
	if(match == 0)
	{
		compr->setLongitud(0);
		contextos[posCtx]->sumarPuntaje(0,PUNTAJE_RESTA);
		bool valeCero = false;
		bool finEjec = false;
		int posRepetido = -1;
		int aux = 1;
		Prediccion* pred;
		while(aux < size && !finEjec)
		{
			aux++;
			pred = contexto->getPrediccionEnPos(aux);
			if( pred->getPuntaje() == 0)
			{
				if( pred->getCaracter(bloque) != bloque.getCaracterEnPos(posCaracterActual)) 
				{
					valeCero = true;
					posRepetido = aux;
				} else 
				{
					pred->setPosicion(posCaracterActual);
					pred->setPuntajeInicial();
					contexto->reordenar(aux);
					valeCero = false;
					finEjec = true;
				}
					
			} else
			{
				if( pred->getCaracter(bloque) == bloque.getCaracterEnPos(posCaracterActual)) 
				{
					pred->setPosicion(posCaracterActual);
					pred->sumarPuntaje(PUNTAJE_SUMA);
					contexto->reordenar(aux);
					valeCero = false;
					finEjec = true;
				} 
			}
		}
		
		if(contexto->estaLLena())
		{
			finEjec =true;
			contexto->addPrediccion(compr->getPosicionCaracterActual());
		}
		
		if(valeCero && !finEjec)
		{
			pred = contexto->getPrediccionEnPos(posRepetido);
			pred->setPosicion(posCaracterActual);
			pred->setPuntajeInicial();
			contexto->reordenar(posRepetido);
		}
	}
	
	// Si hubo match sumo puntaje en la primer posición y le resto al resto. No es necesario
	// reordenar ya que el primer elemento seguirá siendo el de mayor puntaje.
	if( match != 0)
	{
		compr->setLongitud(match);
		contexto->sumarPuntaje(0,PUNTAJE_SUMA);
		int aux = 1;
		Prediccion pred;
		while(aux < size)
		{
			contexto->getPrediccionEnPos(aux)->sumarPuntaje(PUNTAJE_RESTA);
		}
	}
	
	return compr;
}

int main() {
	Indice *ind = new Indice();
	char car1 = 'l';
	char car2 = ' ';
	int a =(int) car1;
	std::cout<<a<<" ";
	a = (int) car2;
	std::cout<<a<<" ";
	int aux = ind->obtenerPosContexto(car1,car2);
	std::cout<<aux<<" ";
	return 0;
}